

#include <iostream>
#include <cassert>
using namespace std ;

const int max_capacity = 20 ; // if client specifies no max_capacity
const int EMPTY = -6969 ; // constant defining empty, hopefully 
						  // client doesn't use this number in data

// the queue class begins here
class queue{
private:
	int q_front ;  // index of front of the queue
	int max_capacity ; // max_capacity for the queue
	int q_length ;  // length (or number of elements in queue)
	int * q ;      // the array the queue is stored in
	bool empty(void)const{return (this->q_length == 0) ;}
	bool full(void)const{return (this->q_length == this->max_capacity);}
public:
	queue(void){  // constructor when no max_capacity is specified
		this->q_front = 0 ;
		this->q_length = 0 ;
		this->max_capacity = max_capacity ; // use global max_capacity
		q = new int[this->max_capacity] ;
		clear() ;  // set every element to EMPTY constant
	}
	queue(int max_capacity){  // constructor with max_capacity
		if(this->max_capacity <= 0) this->max_capacity = max_capacity ;
		this->q_front = 0 ; 
		this->q_length = 0;
		this->max_capacity = max_capacity ; // use client's max_capacity
		q = new int[this->max_capacity] ;
		clear() ;  // set every element to EMPTY constant
	}
	~queue(void){delete this->q ;}
	int length(void)const{return (this->q_length) ; } // get queue's length
	bool enqueue(int x){ // append element to back of queue
		if(empty()) this->q_front = 0 ;
		if(full()) return false ;
		int end = this->q_front + this->q_length ;
		if(end >= this->max_capacity)
			end = end % this->max_capacity ;
		this->q[end] = x ;
		this->q_length++ ;
		return true ;
	}
	int dequeue(void){ // retrieve first element from queue, remove it
		if(empty()) return EMPTY ;
		int temp = this->q[this->q_front] ;
		this->q[this->q_front] = EMPTY ;
		this->q_front++ ;
		if(this->q_front >= this->max_capacity) 
			this->q_front = this->q_front % this->max_capacity ;
		this->q_length-- ;
		return temp ;
	}
	void clear(void){  // clear queue
		this->q_length = 0 ;
		for(int i = 0 ; i < this->max_capacity ; i++)
			this->q[i] = EMPTY ;
	}
	void print(void){ // print queue's contents
		cout << "Top of List is Top Priority" << endl ;
		cout << "---------------------------" << endl ;
		cout << "Front:" << this->q_front << endl ;
		cout << "Length:" << this->q_length << endl ;
		cout << "Max Capacity:" << this->max_capacity << endl ;
		if(empty()) {cout << "Empty Queue!" << endl ; return ;}
		int counter = 1 ;
		int end = this->q_front + this->q_length ;
		if(end >= this->max_capacity)
			end = end % this->max_capacity ;
		for(int i = this->q_front ; counter <= this->q_length; i++, counter++){
			if(i >= max_capacity) 
				i = 0 ;
			cout << "Data " << counter << ".) " << this->q[i] << endl ;
		}
	}
}; // end of queue class


// main, driver program
int main(){
	int num ;  // used for keyboard input
	cout << "What size queue?" << endl ;
	cin >> num ;
	queue q(num) ; // create queue named q of size num
	char input ;
	while(true){
		// main menu
		cout << "What would you like to do?" << endl ;
		cout << "(E)nqueue" << endl ;
		cout << "(D)equeue" << endl ;
		cout << "(C)lear all" << endl ;
		cout << "(L)ength of Queue" << endl ;
		cout << "(P)rint Queue" << endl ;
		cout << "(Q)uit" << endl ;
		cin >> input ;
		switch(input){
		case 'E':
		case 'e':
			cout << "Enter number to enqueue:" << endl ;
			cin >> num ;
			if(q.enqueue(num)) 
				cout << "Enqueue successful!" << endl ;
			else 
				cout << "Queue is full, failure!" << endl ;
			break ;
		case 'D':
		case 'd':
			num = q.dequeue() ;
			if(num == EMPTY) 
				cout << "Queue was empty!" << endl ;
			else
				cout << "Number dequeued was " << num << endl ;
			break ;
		case 'C':
		case 'c':
			q.clear() ;
			break ;
		case 'L':
		case 'l':
			cout << "Length is " << q.length() << endl ;
			break ;
		case 'P':
		case 'p':
			q.print() ;
			break ;
		case 'Q':
		case 'q':
			return 0 ;
		}
	}
}

